#pragma once

#include "ofTexture.h"
#include "ofVideoBaseTypes.h"

//---------------------------------------------
class ofVideoPlayer : public ofBaseVideoDraws {
public:
	ofVideoPlayer();
	ofVideoPlayer(const of::filesystem::path & fileName);

	bool load(const of::filesystem::path & fileName);
	void loadAsync(const of::filesystem::path & fileName);
	[[deprecated("Use load")]]
	bool loadMovie(const of::filesystem::path & fileName);


	/// \brief Get the path to the loaded video file.
	///
	/// If no video file is loaded this returns an empty string.
	///
	/// \returns A path to the loaded video or an empty string if not loaded.
	of::filesystem::path				getMoviePath() const;

	bool				setPixelFormat(ofPixelFormat pixelFormat);
	ofPixelFormat		getPixelFormat() const;

	/// \brief Closes the movie file and releases its resources.
	///
	/// This is an alias for close().
	///
	/// \sa close()
	void 				closeMovie();
	/// \brief Closes the movie file releases its resources.
	///
	/// This is an alias for closeMovie().
	///
	/// \sa closeMovie()
	void 				close();

	/// \brief Update the video player's internal state to continue playback.
	///
	/// If normal video playback is desired, this method is usually called
	/// once per animation frame inside of ofApp::update().
	void				update();
	void 				play();
	void 				stop();

	bool 				isFrameNew() const;
	ofPixels& 			getPixels();
	const ofPixels&		getPixels() const;
	[[deprecated("Use getPixels()")]]
	ofPixels&	getPixelsRef();
	[[deprecated("Use getPixels()")]]
	const ofPixels&  getPixelsRef() const;
	float 				getPosition() const;
	float 				getSpeed() const;
	float 				getDuration() const;
	bool				getIsMovieDone() const;

	void 				setPosition(float pct);
	void 				setVolume(float volume);
	void 				setLoopState(ofLoopType state);
	ofLoopType			getLoopState() const;
	void   				setSpeed(float speed);
	void				setFrame(int frame);

	void 				setUseTexture(bool bUse);
	bool 				isUsingTexture() const;
	ofTexture &			getTexture();
	const ofTexture &	getTexture() const;
	[[deprecated("Use getTexture")]]
	ofTexture &			getTextureReference();
	[[deprecated("Use getTexture")]]
	const ofTexture &	getTextureReference() const;
	std::vector<ofTexture> & getTexturePlanes();
	const std::vector<ofTexture> & getTexturePlanes() const;
	void 				draw(float x, float y, float w, float h) const;
	void 				draw(float x, float y) const;
	using ofBaseDraws::draw;
	/// \brief Binds the video texture to the current rendering context.
	///
	/// For advanced users who need to manually manage texture drawing
	/// without calling draw(). Only binds the texture if one exists.
	///
	/// \sa ofTexture::bind()
	/// \sa http://www.opengl.org/sdk/docs/man4/html/glBindTexture.xhtml
	void 				bind() const;
	/// \brief Unbinds the video texture from the current rendering context.
	///
	/// For advanced users who need to manually manage texture drawing
	/// without calling draw(). Only binds the texture if one exists.
	///
	/// \sa ofTexture::unbind()
	void 				unbind() const;

	void				setAnchorPercent(float xPct, float yPct);
	void				setAnchorPoint(float x, float y);
	void				resetAnchor();

	void 				setPaused(bool bPause);

	int					getCurrentFrame() const;
	int					getTotalNumFrames() const;

	void				firstFrame();
	void				nextFrame();
	void				previousFrame();

	float 				getHeight() const;
	float 				getWidth() const;

	bool				isPaused() const;
	bool				isLoaded() const;
	bool				isPlaying() const;
	bool 				isInitialized() const;

	/// \brief Set the internal video player implementation.
	///
	/// Advanced users may find it useful to set a custom internal video
	/// player implementation. The custom video player must implment the
	/// ofBaseVideoPlayer interface.
	///
	/// \param newPlayer Shared pointer to the new video player that extends
	/// from ofBaseVideoPlayer.
	void				setPlayer(std::shared_ptr<ofBaseVideoPlayer> newPlayer);
	/// \brief Get a pointer to the internal video player implementation.
	///
	/// This returns a pointer to the ofBaseVideoPlayer interface. For
	/// implementation-specfic features, this can be cast to the subtype
	/// using dynamic_cast<MyVideoPlayerImplementation>(getPlayer()) or the
	/// templated getPlayer<MyVideoPlayerImplementation>() method.
	///
	/// \returns A pointer to the internal video player implementation.
	std::shared_ptr<ofBaseVideoPlayer>	getPlayer();
	/// \brief Get a const pointer to the internal video player implementation.
	///
	/// This returns a pointer to the ofBaseVideoPlayer interface. For
	/// implementation-specfic features, this can be cast to the subtype
	/// using dynamic_pointer_cast<MyVideoPlayerImplementation>(getPlayer())
	/// or the templated getPlayer<MyVideoPlayerImplementation>() method.
	///
	/// \returns A const pointer to the internal video player implementation.
	const std::shared_ptr<ofBaseVideoPlayer>	getPlayer() const;

	/// \brief Get a pointer to the internal video player implementation.
	///
	/// Calling getPlayer<MyVideoPlayerImplementation>() is equivalent to
	/// dynamic_pointer_cast<MyVideoPlayerImplementation>(getPlayer()).
	///
	/// \returns A pointer to the internal video player implementation or
	///			 nullptr if the cast fails.
	template<typename PlayerType>
	std::shared_ptr<PlayerType> getPlayer(){
		return std::dynamic_pointer_cast<PlayerType>(getPlayer());
	}

	/// \brief Get a const pointer to the internal video player implementation.
	///
	/// Calling getPlayer<MyVideoPlayerImplementation>() is equivalent to
	/// dynamic_pointer_cast<MyVideoPlayerImplementation>(getPlayer()).
	///
	/// \returns A const pointer to the internal video player implementation
	///			 or nullptr if the cast fails.
	template<typename PlayerType>
	const std::shared_ptr<PlayerType> getPlayer() const{
		return std::dynamic_pointer_cast<PlayerType>(getPlayer());
	}

private:
	/// \brief Initialize the default player implementations.
	void initDefaultPlayer();
	/// \brief A pointer to the internal video player implementation.
	std::shared_ptr<ofBaseVideoPlayer>		player;
	/// \brief A collection of texture planes used by the video player.
	std::vector<ofTexture> tex;
	/// \brief A pointer to the internal player's texture if available.
	///
	/// Video players that implement ofBaseVideoPlayer::getTexturePtr()
	/// can provide a pointer to an internal texture. When possible,
	/// ofVideoPlayer will use the internal texture to avoid extra pixel
	/// copies.
	ofTexture * playerTex;
	/// \brief True if the video player is using a texture.
	bool bUseTexture;
	/// \brief The internal pixel format.
	mutable ofPixelFormat internalPixelFormat;
	/// \brief The stored path to the video's path.
	of::filesystem::path moviePath;
};
